Skip to content

Limit the element count of fixed-length lists#2537

Open
eyupcanakman wants to merge 1 commit into
bytecodealliance:mainfrom
eyupcanakman:fix/fixed-length-list-size-limit-2416
Open

Limit the element count of fixed-length lists#2537
eyupcanakman wants to merge 1 commit into
bytecodealliance:mainfrom
eyupcanakman:fix/fixed-length-list-size-limit-2416

Conversation

@eyupcanakman

Copy link
Copy Markdown
Contributor

Fixed-length lists were only checked for zero elements, with no upper bound, so a list of up to 4294967295 elements passed validation. The count then flows to consumers and overflows their canonical ABI size calculations. Cap the element count at 1 Gi, the limit suggested on the issue.

Closes #2416.

Fixed-length lists were only checked for zero elements, with no upper bound, so a list of up to 4294967295 elements passed validation. The count then flows to consumers and overflows their canonical ABI size calculations. Cap the element count at 1 Gi, the limit suggested on the issue.

Closes bytecodealliance#2416.
@eyupcanakman eyupcanakman requested a review from a team as a code owner June 6, 2026 12:07
@eyupcanakman eyupcanakman requested review from fitzgen and removed request for a team June 6, 2026 12:07
@eyupcanakman

Copy link
Copy Markdown
Contributor Author

While here I noticed this bounds the count rather than the resulting byte size. SizeAlign in wit-parser and wit-dylib still assume a fixed-length list's size fits a u32/usize, so a list<u64> near the cap or a nested list overflows. That path already exists on main, independent of this change. I can open a separate issue or PR for it if that's worth doing.

@alexcrichton

Copy link
Copy Markdown
Member

Thanks for the PR, but yeah what I was looking for in the original issue was a bound on the byte-size of the list so downstream consumers don't have to worry as much about integer overflow. In that sense I think the check here should be on the in-memory-byte-size rather than the number of elements.

@eyupcanakman

Copy link
Copy Markdown
Contributor Author

Switched the check to the in-memory byte size, element ABI size times length, with a 1 GiB limit. Two questions before I finish it.

Computing the element size means walking the element type, so a deeply nested chain of fixed-length lists can blow the stack. Want the size stored per type next to the existing TypeInfo, or is the walk fine?

The limit also rejects wit-deep-list.wit now, since its outer type is 4 GiB. Is that the behavior you want or should nesting be bounded differently?

@alexcrichton

Copy link
Copy Markdown
Member

The walk should be fine, yeah, we've got other mechanisms of limiting the depth of a type for this exact reason. Most of wasm-tools/external tooling will walk the structure of a type recursively so the maximum depth is bounded. If you're actually blowing the stack though and this isn't hypothetical that may mean we have a hole in our checks somewhere...

Otherwise though yeah feel free to change the wit-deep-list.wit type, no need to keep that working exactly as-is

@eyupcanakman

Copy link
Copy Markdown
Contributor Author

Confirmed it's real, not hypothetical. A nested fixed-length-list chain overflows the stack on the binary validate path around 80k deep where the element-count version was fine, and nothing bounds that depth (MAX_WASM_SUBTYPING_DEPTH only covers core types), so option/result/map nesting can hit it too. Want me to add a depth limit on those arms or cache each type's size?

@alexcrichton

Copy link
Copy Markdown
Member

Ah ok I'm mistakenly remembering where things are. Wasmtime has a depth check but wasmparser does not, and that's why I thought the issue would be solved here (I thought it was here, too). In light of that WDYT about maybe redefining TypeInfo's current size to being a byte size rather than an "effective type size". The latter has always been a bit of a murky metric anyway and by using byte size that's a bit more clearly defined. This probably wouldn't represent literal byte size though as dealing with things like alignment would be a bit too annoying here, but having records be the sum of their parts and variants be the maximum of their leaves seems reasonable enough in terms of calculating this. Being off by a constant-factor-of-sorts seems like it wouldn't break the bank here in calculations for fixed-length-lists.

Although... saying all that out loud, maybe it's just best to be relatively restrictive on fixed-length-list sizes. It's probably not actually true that being off by a small factor wouldn't matter in practice because when multiplying by the length of a list that blows up the error factor here and magnifies any miscalculation.


Stepping back a bit, the general goal of the issue here is to ensure that overflow checks aren't needed anywhere else in the system that handles fixed-length-lists and it's just the validator here that might need overflow checks. Just having a fixed limit on the size of a list isn't sufficient for this because eventually the calculation for "how big is this list" is going to overflow. Without precisely tracking in-memory size, though, I'm not sure if it's possible to do that otherwise. I forget if wasmparser is otherwise handling canonical ABI layout anywhere right now (I don't think it is, that feels more a wit-parser thing).

Given all that, it might be the case that preventing overflows is basically just not possible here. If that's the case then I suspect that this PR may be the best way forward of "some fixed limit that's big enough for everyone" to avoid "infinity" cases, but otherwise all downstream usage of fixed-length-lists will still need to handle overflow. The only other alternative I can think of is to precisely track canonical ABI size in a manner similar to TypeInfo and go from there, but that's a much bigger lift for this and I'm not sure if it's worth it...

(sorry for the sort of stream-of-consciousness)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow up from wasmtime: Check reasonable sizes for fixed-size-lists in validator

2 participants